//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         XORT virtual machine SDK
// FILE:            xort_sdk.h - definitions for third-party developers
// AUTHOR:          Vladimir Gumenuk
// DATE:            28-Jul-20014
// NOTES:           
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#ifdef BUILD_FOR_PC
#define FASTCALL __fastcall
#define STDCALL  __stdcall
#else
#define FASTCALL
#define STDCALL
#endif

typedef unsigned int        dword;
typedef unsigned char       byte;
typedef unsigned short      word;
typedef unsigned char*      lpbyte;

#ifdef BUILD_FOR_MAC
typedef long long           qlong;
typedef unsigned long long  qword;
#else
typedef __int64             qlong;
typedef unsigned __int64    qword;
#endif

typedef double              real;
typedef char*               lpstr;
typedef const char*         lpcstr;

struct xunknown
{
    virtual dword AddRef() = 0;
    virtual dword Release() = 0;
    virtual dword GetRefCount() = 0;
};

enum XNIVariantTypeCodes
{
    xni_v  = 0x00,
    xni_s1 = 0x10,
    xni_u1 = 0x20,
    xni_s2 = 0x30,
    xni_u2 = 0x40,
    xni_s4 = 0x50,
    xni_u4 = 0x60,
    xni_s8 = 0x70,
    xni_u8 = 0x80,
    xni_r4 = 0x90,
    xni_r8 = 0xA0,
    xni_ptr= 0xB0,
    xni_str= 0xC0,
    xni_bin= 0xD0,
};

#pragma pack(1)
struct XNIVariant {
    byte bType;
    dword dwSize;    // relevant for binary buffers only
    union {
        char        _s1;
        byte        _u1;
        short       _s2;
        word        _u2;
        int         _s4;
        dword       _u4;
        qlong       _s8;
        qword       _u8;
        float       _r4;
        real        _r8;
        xunknown*   _p;
        lpstr       _str;
        lpbyte      _bin;
    };
    XNIVariant() {
        bType = 0;
        _u8 = 0;
    }
    XNIVariant(const XNIVariant& x) {
        bType = x.bType;
        _u8 = x._u8;
        if( bType == xni_ptr && _p )
            _p->AddRef();
    }
    ~XNIVariant() {
        Clear();
    }
    void operator= (int x) { // :) support for array, to reat this object as simple type :)
        Clear();
    }
    void operator= ( const XNIVariant& x ) {
        if( &x == this ) return;
        Clear();
        bType = x.bType;
        _u8 = x._u8;
        dwSize = x.dwSize;
        if( bType == xni_ptr && _p ) {
            _p->AddRef();
        } else if( bType == xni_bin ) {
            _bin = new byte[ x.dwSize ];
            memcpy( _bin, x._bin, x.dwSize );
        } else if( bType == xni_str ) {
            _str = new char[ x.dwSize + 1 ];
            strcpy( _str, x._str );
        }
    }
    void Clear() {
        if( bType == xni_ptr && _p )
            _p->Release();
        else if( bType == xni_bin || bType == xni_str )
            delete []_bin;
        
        bType = 0;
        _u8 = 0;
        dwSize = 0;
    }
    inline operator char() const { return _s1; }
    inline operator byte() const { return _u1; }
    inline operator short() const { return _s2; }
    inline operator word() const { return _u2; }
    inline operator int() const { return _s4; }
    inline operator dword() const { return _u4; }
    inline operator qlong() const { return _s8; }
    inline operator qword() const { return _u8; }
    inline operator float() const { return _r4; }
    inline operator real() const { return _r8; }
    inline operator xunknown*() const { return _p; }
    inline operator lpcstr() const { return _str; }
    inline operator lpbyte() const { return _bin; }
        
    inline void SetValue(char  val) { _s1 = val; }
    inline void SetValue(byte  val) { _u1 = val; }
    inline void SetValue(short val) { _s2 = val; }
    inline void SetValue(word  val) { _u2 = val; }
    inline void SetValue(int   val) { _s4 = val; }
    inline void SetValue(dword val) { _u4 = val; }
    inline void SetValue(qlong val) { _s8 = val; }
    inline void SetValue(qword val) { _u8 = val; }
    inline void SetValue(float val) { _r4 = val; }
    inline void SetValue(real  val) { _r8 = val; }
    inline void SetValue(xunknown* val) { if( bType == xni_ptr && _p ){ _p->Release(); _p = 0; } _p = val; if( _p ) _p->AddRef(); }
    inline void SetValue(lpstr val, dword _Size) { Clear(); _str = val; dwSize = _Size; bType = xni_str; }
    inline void SetValue(lpbyte pBuf, dword _Size) { Clear(); _bin = pBuf; dwSize = _Size; bType = xni_bin; }
};
#pragma pack()

// Represents an array of variants
struct XNIVariantArray : xunknown
{
    virtual dword GetCount() = 0;
    virtual int   GetValue( dword dwIdx, XNIVariant& vVal ) = 0;
};

// This interface should be supported by an object implemented in third-party dll
struct XortNativeInterface : xunknown
{
    // Returns the object name
    virtual lpcstr GetName() = 0;

    // Invokes the object method by name
    virtual int Invoke( lpcstr lpszName, XNIVariantArray *pArgs, XNIVariant& vResultOut ) = 0;
    
    // assigns new value to the internal variable by name
    virtual int Put( lpcstr lpszName, XNIVariant& Value ) = 0;
    
    // returns the value of the internal variable
    virtual int Get( lpcstr lpszName, XNIVariant& Value ) = 0;
};


#ifdef __cplusplus
extern "C" {
#endif

// This function should be exported by the module that contains target object
int STDCALL create_xort_object( lpcstr lpszName, xunknown **ppOut );

#ifdef __cplusplus
} // extern "C" {
#endif